<script setup lang="ts">
import {onMounted, ref} from "vue";
import MarkdownIt from "markdown-it";
import './less/index.less'
import {getUUID} from "@/utils/common.ts";
import hljs from 'highlight.js/lib/core'
import bashLanguage from 'highlight.js/lib/languages/bash';
import markdownItAnchor from 'markdown-it-anchor'
import {slugify} from "@/utils/slugify.ts";

hljs.registerLanguage('bash', bashLanguage);

const markdownText = ref('')
const htmlVal = ref<any>('')
let items = ref<any[]>([])


// 实例化markdown-it
const md = new MarkdownIt({
  html: true,
  // 自动将类似url的文本转换为链接
  linkify: true,
  typographer: true,
  langPrefix: 'language-', // 给围栏代码块的 CSS 语言前缀。对于额外的高亮代码非常有用。

  // 高亮的语法规范，有代码块时再使用
  highlight: (code, lang) => {
    // 通过id去获取代码块，并复制到剪贴板，更加方便
    const codeId = getUUID()
    const copyCode = `<div class="code-copy-btn" onclick='window.copyToClipboard("${codeId}")'>复制代码</div>`
    // 添加class="hljs"类，给代码块添加高亮样式
    return `<pre class="hljs pre-warp"><code id="${codeId}" class="code-warp">${hljs.highlight(lang, code).value}</code>${copyCode}</pre>`
  }
})

md.use(markdownItAnchor, {
  slugify, //生成有效url的自定义函数 function，
  permalink: markdownItAnchor.permalink.linkInsideHeader({
    symbol: `
          <span aria-hidden="true" class="anchor">#</span>
        `
  }),
  permalinkBefore: true,
  permalinkSymbol: '#',
  permalinkAttrs: () => ({ 'aria-hidden': true }),
  tabIndex: false
})

// 复制代码到粘贴板
window.copyToClipboard = (codeId = '') => {
  try{
    if(codeId){
      const code = document.getElementById(codeId)?.innerText
      if(code){
        navigator.clipboard.writeText(code)
      }else{
        throw new Error('复制失败，请检查代码块是否存在')
      }
    }else{
      throw new Error('复制失败，请检查代码块是否存在')
    }
  }catch(e){
    console.log(e)
  }


}

// 解析markdown文本，提取标题，生成锚点目录。目前读取二级标题为目录内容
const handleAnchorItem = () => {
  if(markdownText.value){
    // 获取所有标题内容
    const regex = /##(\s+)(.+)/g
    const found = markdownText.value.match(regex)
    if(found && found.length > 0){
      found.map((item) => {
        // 上面的正则表达式会将'### '、'#### '这类的标题也匹配进来，因此在这再进行过滤
        if (!markdownText.value.includes(`#${item}`)) {
          const title = item.replace('## ', '')

          items.value.push({
            key: title,
            href: `#${title}`,
            title: title
          })
        }
      })
    }

    console.log(items.value)

  }
}

// 动态加载md文件资源
const handleShowContent = () => {
  /**
   * 步骤：
   * 1、动态加载 md 文件内容
   * 2、md 内容通过 MarkdownIt 赋值给 htmlVal
   */

  // vite：资源可以使用 ?raw 后缀声明作为字符串引入
  import('./mdFile/introduction.md?raw').then(content => {
    markdownText.value = content.default
    // 先处理内容，提取标题，生成锚点目录，再进行渲染
    handleAnchorItem()
    htmlVal.value = md.render(content.default)
  })

}

// 页面加载完成后，获取html内容
onMounted(() => {
  handleShowContent()
})

/**
 * 1、必须配置getContainer，否则affix失效
 * 2、如果‘warp-left’类没有设置height 和 overflow-y，锚点目录则不会随页面滚动而滚动。
 * */
const getContainer = () => document.querySelector('.warp-left')

</script>
<template>
  <div class="markdown-wrap container">
    <div class="warp-left">
      <div v-html="htmlVal"></div>
    </div>
    <div class="warp-right">
      <a-anchor wrapper-class="anchor-wrapper" :items="items" :affix="false" :get-container="getContainer" />
    </div>
  </div>
</template>

<style lang="less">
.container{
  padding: 0 20px;
  width: calc(100vw - 100px);
  display: flex;
  .warp-left{
    flex: 1;
    height: calc(100vh - 30px);
    overflow-y: auto;
  }

  .warp-right {
    width: 160px;
    .anchor-wrapper {
      position: fixed;
      top: 130px;
      right: 30px;
      width: 160px;
      background-color: #fff;
      z-index: 999;
    }

    .ant-anchor-link-title {
      overflow: hidden;
      white-space: nowrap;
      text-overflow: ellipsis;
      position: relative;
      display: block;
      margin-block-end: 3px;
      color: rgba(0, 0, 0, 0.88);
      transition: all 0.3s;
    }
  }
}

</style>
